home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 17767 < prev    next >
Encoding:
Text File  |  1996-08-05  |  3.5 KB  |  142 lines

  1. Path: grimsel.zurich.ibm.com!usenet
  2. From: Keith Whittingham <wgk@zurich.ibm.com>
  3. Newsgroups: comp.lang.c++
  4. Subject: 'chained': It would be nice if...
  5. Date: Wed, 17 Apr 1996 15:17:16 -0700
  6. Organization: IBM Zurich Research Laboratory
  7. Message-ID: <31756DEC.5215@zurich.ibm.com>
  8. NNTP-Posting-Host: pine.zurich.ibm.com
  9. Mime-Version: 1.0
  10. Content-Type: text/plain; charset=us-ascii
  11. Content-Transfer-Encoding: 7bit
  12. X-Mailer: Mozilla 2.01 (Win16; I)
  13.  
  14. Three or four times I've find myself needing a construct which I
  15. think is missing from C++ (or at least is inaccessable).
  16.  
  17. A keyword, say 'chained', to have a similar effect to that of
  18. the virtual destructor. e.g.
  19.  
  20. class Base
  21.   {
  22.   public:
  23.     virtual void vMember(void);
  24.     chained void cMember(void);
  25.   };
  26.  
  27. class Derived:
  28.   public Base
  29.   {
  30.   public:
  31.     void vMember(void);
  32.     void cMember(void);
  33.   };
  34.  
  35. Calling Derived::vMember() executes the code contained in the body
  36. Derived::vMember() whereas calling Derived::cMember() would
  37. execute the code contained in the body Base::cMember() and then
  38. the code contained in Derived::cMember(). This similar and not
  39. identical to the chaining in a virtual destructor in as much as
  40. the child destructor gets called before the parents.
  41.  
  42. Why? Well mainly to give the class designer the ability to force
  43. users of his class to call the base function when overriding. This 
  44. is best described with an example:
  45.  
  46. class Node { /*...*/ };
  47.  
  48. class Bag
  49.   {
  50.   public:
  51.     Bag() { count = 0; Fic = 0; }
  52.     virtual void Add(Node &n)
  53.       {
  54.       LinkIn(n);
  55.       count++;
  56.       }
  57.     int Count(void) const { return count; }
  58.     void LinkIn(Node &New);
  59.  
  60.   protected:
  61.     int count;
  62.   private:
  63.     Node *Fic;  // First in chain
  64.   };
  65.  
  66.  
  67. class SortedBag:
  68.   public Bag
  69.   {
  70.   public:
  71.     void Add(Node &n)
  72.       {
  73.       LinkIn(n);
  74.       Sort();
  75.       count++;  // !! Must do this !!
  76.       }
  77.     void Sort(void);
  78.   };
  79.  
  80. We can see the code for Add() and we can see that if we were to
  81. override Add() with, say, SortedBag::Add() that we must ensure
  82. that count is incremented when the object is added to the bag.
  83.  
  84. Redefining Add() as 'chained' in the base class Bag
  85.  
  86. class Node { /*...*/ };
  87.  
  88. class Bag
  89.   {
  90.   public:
  91.     Bag() { count = 0; Fic = 0; }
  92.     chained void Add(Node &n)
  93.       {
  94.       LinkIn(n);
  95.       count++;
  96.       }
  97.     int Count(void) const { return count; }
  98.     void LinkIn(Node &New);
  99.  
  100.   private:
  101.     int count;
  102.     Node *Fic;  // First in chain
  103.   };
  104.  
  105.  
  106. class SortedBag:
  107.   public Bag
  108.   {
  109.   public:
  110.     void Add(Node &n)
  111.       {
  112.       Sort();
  113.       }
  114.     void Sort(void);
  115.   };
  116.  
  117. The class designer knows that the semantics of Add() are not lost
  118. and does not need to advertise the fact that count must be 
  119. incremented if Add() is overriden. There is a second advantage in
  120. that the member 'count' does not need to be exposed albeit only as 
  121. a protected member.
  122.  
  123. The real advantage of a chained keyword is to follow, without 
  124. really knowing, the class hierarchy. I recently implemented 
  125. a dynamic_cast type function by using an abstract base class 
  126. with a return ClassType() member in the base class and a 
  127. conversion operator. In order to allow a cast it was necessary
  128. to traverse the class hierarchy in order to ascertain if indeed
  129. the object was of the target class type. The only way I found of
  130. achieving this functionality was to provide a ParentChild() 
  131. macro to be used in each class which defined a function which
  132. had the semantic "return OK if I am same type as target or 
  133. ask my parent".
  134.  
  135. Interested to hear what you think or how this might be
  136. implemented with writing a compiler!
  137.  
  138.  
  139. -- 
  140. Keith Whittingham
  141. wgk@zurich.ibm.com
  142.